using System;
using System.Web;
using System.Web.Security;
using System.Collections;
using System.ServiceModel;
using System.Collections.Generic;
using System.Configuration;
using SecurityFoundation;
using SecurityFoundation.Entities;

/// <summary>
/// Summary description for MemberService
/// </summary>
namespace SecurityAgent
{
    [SecurityExceptionHandler(AttributePriority=99)]
    public class MembershipProviderService : IMembershipProviderService
    {
        //protected bool AllowAdminAccess(string applicationKey, string userToken)
        //{
        //    ApplicationDefination app = Repository.GetApplicationDefinition(new Guid(applicationKey));
        //    Realm realm = Repository.GetRealm(app.Realm);
        //    SecurityToken token = Repository.GetToken(new Guid(userToken));

        //    RoleProviderService roleService = new RoleProviderService(); 
        //    return roleService.IsUserInRole(realm.AdminApplication.ToString(), userToken, string.Empty, "ADMIN");
            
        //}

        //protected void AssertAdminAccess(string applicationKey, string operatorToken, string operation)
        //{
        //    if (String.IsNullOrEmpty(operatorToken))
        //        throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = "Membership", Operation = operation });

        //    RoleProviderService roleService = new RoleProviderService();

        //    if (!roleService.IsAuthorizedAdmin(applicationKey, operatorToken))
        //    {
        //        throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = "Membership", Operation = operation });
        //    }

        //}

        //protected void AssertAdminOrSelfAccess(string applicationKey, string operatorToken, string userName, string operation)
        //{
        //    if (String.IsNullOrEmpty(operatorToken))
        //        throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = "Membership", Operation = operation });

        //    RoleProviderService roleService = new RoleProviderService();

        //    if (!roleService.IsAuthorizedAdmin(applicationKey, operatorToken))
        //    {
        //        SecurityPrincipal op = ObtainServiceUserByToken(applicationKey, operatorToken);
        //        if (op == null || op.UserName != userName)
        //               throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = "Membership", Operation = operation });
        //    }

        //}

        protected System.Web.Security.MembershipProvider GetProvider(string applicationKey)
        {
            
            System.Web.Security.MembershipProvider provider;

            if (applicationKey == null)
            {
                //throw new FaultException(new FaultReason("Application Key Not Provided"), new FaultCode("Invalid Parameter"));
                throw new ArgumentNullException("Application Key Not Provided");
            }

            try
            {
                ApplicationDefination appDef = Repository.GetApplicationDefinition(new Guid(applicationKey));

                Realm realm = Repository.GetRealm(appDef.Realm);

                if (realm.AuthenticationProviderName != null)
                {
                    provider = Membership.Providers[realm.AuthenticationProviderName];
                }
                else
                    provider = Membership.Provider;

                return provider;
            }
            catch (Exception ex)
            {

                //throw new FaultException(new FaultReason("Error In Getting Realm For " + applicationKey + ":" + ex.Message), new FaultCode("Error"));
                throw new Exception("Error In Getting Realm For " + applicationKey + ":" + ex.Message);
            }
        }

        protected System.Web.Security.MembershipProvider GetProviderByName(string providerName)
        {
            System.Web.Security.MembershipProvider provider;

            if (providerName != null)
            {
                provider = Membership.Providers[providerName];
            }
            else
                provider = Membership.Provider;

            return provider;

        }



        protected SecurityAgent.SecurityPrincipal ConvertUser(System.Web.Security.MembershipUser user)
        {
            if (user == null) return null;
            SecurityAgent.SecurityPrincipal membershipUser = new SecurityAgent.SecurityPrincipal();
            membershipUser.Comment = user.Comment;
            membershipUser.CreationDate = user.CreationDate;
            membershipUser.Email = user.Email;
            membershipUser.IsApproved = user.IsApproved;
            membershipUser.IsLockedOut = user.IsLockedOut;
            membershipUser.IsOnline = user.IsOnline;
            membershipUser.LastActivityDate = user.LastActivityDate;
            membershipUser.LastLockoutDate = user.LastLockoutDate;
            membershipUser.LastLoginDate = user.LastLoginDate;
            membershipUser.LastPasswordChangedDate = user.LastPasswordChangedDate;
            membershipUser.PasswordQuestion = user.PasswordQuestion;
            membershipUser.ProviderUserKey = user.ProviderUserKey;
            membershipUser.UserName = user.UserName;
            return membershipUser;
        }

        protected System.Web.Security.MembershipUser ConvertUser(SecurityAgent.SecurityPrincipal user)
        {
            if (user == null) return null;
            System.Web.Security.MembershipUser membershipUser =
              new System.Web.Security.MembershipUser("SecurityAgentServiceProvider",
                user.UserName,
                user.ProviderUserKey,
                user.Email,
                user.PasswordQuestion,
                user.Comment,
                user.IsApproved,
                user.IsLockedOut,
                user.CreationDate,
                user.LastLoginDate,
                user.LastActivityDate,
                user.LastPasswordChangedDate,
                user.LastLockoutDate);
            return membershipUser;
        }

        //protected List<MembershipUser> BuildUserList(System.Web.Security.MembershipUserCollection collection)
        //{
        //    if (collection == null) return null;
        //    List<MembershipUser> list = new List<MembershipUser>();
        //    foreach (System.Web.Security.MembershipUser user in collection)
        //    {
        //        list.Add(ConvertUser(user));
        //    }
        //    return list;
        //}

        //public MembershipProvider()
        //{

        //    //Uncomment the following line if using designed components 
        //    //InitializeComponent(); 
        //}

        #region IMembershipProviderService Members

        public bool GetEnablePasswordReset(string applicationKey)
        {
            return GetProvider(applicationKey).EnablePasswordReset;
        }

        public bool GetEnablePasswordRetrieval(string applicationKey)
        {
            return GetProvider(applicationKey).EnablePasswordRetrieval;
        }

        

        public int GetMinRequiredPasswordLength(string applicationKey)
        {
            return GetProvider(applicationKey).MinRequiredPasswordLength;
        }

        public int GetPasswordAttemptWindow(string applicationKey)
        {
            return GetProvider(applicationKey).PasswordAttemptWindow;
        }

        public int GetPasswordFormat(string applicationKey)
        {
            return (int) GetProvider(applicationKey).PasswordFormat;
        }

        public string GetPasswordStrengthRegularExpression(string applicationKey)
        {
            return GetProvider(applicationKey).PasswordStrengthRegularExpression;
        }

        public bool GetRequiresQuestionAndAnswer(string applicationKey)
        {
            return GetProvider(applicationKey).RequiresQuestionAndAnswer;
        }

        public bool GetRequiresUniqueEmail(string applicationKey)
        {
            return GetProvider(applicationKey).RequiresQuestionAndAnswer;
        }


        public int GetMaxInvalidPasswordAttempt(string applicationKey)
        {
            return GetProvider(applicationKey).MaxInvalidPasswordAttempts;
        }


        public int GetMinRequiredNonAlphanumericCharacters(string applicationKey)
        {
            return GetProvider(applicationKey).MinRequiredNonAlphanumericCharacters;
        }

        public bool ChangePassword(string applicationKey, string username, string oldPassword, string newPassword)
        {
            return GetProvider(applicationKey).ChangePassword(username, oldPassword, newPassword);
        }

        public bool ChangePasswordQuestionAndAnswer(string applicationKey, string username, string password, string newPasswordQuestion, string newPasswordAnswer)
        {
            return GetProvider(applicationKey).ChangePasswordQuestionAndAnswer(username, password, newPasswordQuestion, newPasswordAnswer);
        }

        public SecurityPrincipal CreateUser(string applicationKey, string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
        {
            MembershipUser user =  GetProvider(applicationKey).CreateUser(username, password, email, passwordQuestion, passwordAnswer, isApproved, providerUserKey, out status);

            if (user != null) return ConvertUser(user);
            else
                return null;
        }

        [RequireAdminAccess(AttributePriority=10)]
        public bool DeleteUser(string applicationKey, string operatorToken, string username, bool deleteAllRelatedData)
        {
            //AssertAdminAccess(applicationKey, operatorToken, "DeleteUser");
            
            return GetProvider(applicationKey).DeleteUser(username, deleteAllRelatedData);
        }

        public SecurityPrincipalCollection FindUsersByEmail(string applicationKey, string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection users = GetProvider(applicationKey).FindUsersByEmail(emailToMatch, pageIndex, pageSize, out totalRecords);

            SecurityPrincipalCollection sec = new SecurityPrincipalCollection();
            foreach (MembershipUser user in users)
            {
                sec.Add(ConvertUser(user));
            }

            return sec;
        }

        public SecurityPrincipalCollection FindUsersByName(string applicationKey, string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection users = GetProvider(applicationKey).FindUsersByName(usernameToMatch, pageIndex, pageSize, out totalRecords);

            SecurityPrincipalCollection sec = new SecurityPrincipalCollection();
            foreach (MembershipUser user in users)
            {
                sec.Add(ConvertUser(user));
            }

            return sec;
        }

        [RequireAdminAccess(AttributePriority = 10)]
        public SecurityPrincipalCollection GetAllUsers(string applicationKey, string operatorToken, int pageIndex, int pageSize, out int totalRecords)
        {
            MembershipUserCollection users = GetProvider(applicationKey).GetAllUsers(pageIndex, pageSize, out totalRecords);

            SecurityPrincipalCollection sec = new SecurityPrincipalCollection();
            foreach (MembershipUser user in users)
            {
                sec.Add(ConvertUser(user));
            }

            return sec;
        }

        public int GetNumberOfUsersOnline(string applicationKey)
        {
            return GetProvider(applicationKey).GetNumberOfUsersOnline();
        }

        public string GetPassword(string applicationKey, string username, string answer)
        {
            return GetProvider(applicationKey).GetPassword(username, answer);
        }

        public SecurityPrincipal GetUserByUserName(string applicationKey, string username, bool userIsOnline)
        {
            return ConvertUser( GetProvider(applicationKey).GetUser(username, userIsOnline));
        }

        public SecurityPrincipal GetUserByKey(string applicationKey, object providerUserKey, bool userIsOnline)
        {
            return ConvertUser(GetProvider(applicationKey).GetUser(providerUserKey, userIsOnline));
        }

        public SecurityPrincipal ObtainServiceUserByToken(string serviceApp, object userToken)
        {
            SecurityToken token = Repository.GetToken(new Guid(userToken.ToString()));
           
            if (token != null)
            {

                Realm realm = Repository.GetRealm(token.Realm);

                System.Web.Security.MembershipProvider provider = GetProviderByName(realm.AuthenticationProviderName);

                if (provider != null)
                    return ConvertUser(provider.GetUser(token.UserName, true));
            }

            return null;
            
        }

        public bool ExpireToken(string applicationKey, object userToken)
        {
            SecurityToken token = Repository.GetToken(new Guid(userToken.ToString()));

            if (token != null)
            {
                if ( token.SourceApplication != new Guid(applicationKey))
                {
                    throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = token.SourceApplication.ToString().Trim(), Object = "UserToken", Message = "Token was created from a different application", UserToken = userToken.ToString().Trim() });
                }

                return Repository.DeleteUserToken(new Guid(userToken.ToString()));
            }

            return false;

        }


        public string GetUserNameByEmail(string applicationKey, string email)
        {
            return GetProvider(applicationKey).GetUserNameByEmail(email);
        }

        public string ResetPassword(string applicationKey, string username, string answer)
        {
            return GetProvider(applicationKey).ResetPassword(username, answer);
        }

       

        [RequireAdminOrSelfAccess(AttributePriority=10)]
        public void UpdateUser(string applicationKey, string operatorToken, string userName, SecurityPrincipal user)
        {
            //if( String.IsNullOrEmpty(operatorToken))
            //    throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = "User", Operation = "UpdateUser" });
            
            //RoleProviderService roleService = new RoleProviderService();

            //if (!roleService.IsAuthorizedAdmin(applicationKey, operatorToken))
            //{
            //    SecurityPrincipal op = ObtainServiceUserByToken(applicationKey, operatorToken);
            //    if (op == null || op.UserName != user.UserName)
            //        throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = "User", Operation = "UpdateUser" });
            //}

            GetProvider(applicationKey).UpdateUser(ConvertUser(user));
        }

        public bool ValidateUser(string applicationKey, string username, string password)
        {
            return GetProvider(applicationKey).ValidateUser(username, password);
        }

        [RequireAdminAccess(AttributePriority=10)]
        public bool UnlockUser(string applicationKey, string operatorToken, string userName)
        {
            //RoleProviderService roleService = new RoleProviderService();

            //if (!roleService.IsAuthorizedAdmin(applicationKey, operatorToken))
            //    throw new FaultException<UnauthorizedAccessFault>(new UnauthorizedAccessFault { Application = applicationKey, Object = "Roles", Operation = "AddUsersToRoles" });

            return GetProvider(applicationKey).UnlockUser(userName);
        }

        public string ValidateAndRegisterUser(string applicationKey, string username, string password)
        {
            System.Web.Security.MembershipProvider provider = GetProvider(applicationKey);

            if (provider == null)
            {
                throw new FaultException(new FaultReason("Unabled to find realm definition for application" + applicationKey), new FaultCode("Invalid Parameter"));
            }

            bool result = provider.ValidateUser(username, password);

            if (result)
            {
                //MembershipUser user = provider.GetUser(username, false);

                Guid tokenKey = Repository.CreateToken(applicationKey, username);

                //SecurityPrincipal ret = ConvertUser(user);

                //ret.SecurityAgentToken = tokenKey;

                return tokenKey.ToString().Trim();
            }
            else
            {
                return null;
            }
        }

        #endregion
    }
}